/*
 * Copyright 2007-2010 Jeremy Brown.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author <a href="http://jeremy-brown.com">Jeremy Brown</a>
 */


package groovy.prefuse.factory

import groovy.prefuse.impl.action.assignment.*

import prefuse.action.*
import prefuse.action.assignment.*
import prefuse.Visualization
import prefuse.util.*


public class AssignmentFactory extends ActionFactory
{
	private Class klass

	public AssignmentFactory(Class klass)
	{
		this.klass = klass
	}

	boolean isLeaf()
	{
		return false
	}
    
    public Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributes) throws InstantiationException, IllegalAccessException
	{
		builder.context.put("name", attributes.remove("name")) //Action will be added to Visualization with this name
		builder.context.put("predicate", attributes.remove("predicate"))
		
		if(value == null && attributes.assignment)
		{
			value = attributes.remove("assignment")
		}
		
		if(value instanceof EncoderAction)
		{
			return value
		}

		def buildClass
		if(klass)
		{
			buildClass = klass
		}
		else if(value instanceof Class)
		{
			buildClass = value
			value = null
		}
		
		def assignment = null
		
		if(buildClass instanceof Class && EncoderAction.isAssignableFrom(buildClass))
		{
			if(FontAction.equals(buildClass))
			{
				if(attributes.closure)
				{
					assignment = new ClosureFontAction(attributes.remove("closure"))
				}
				else if(attributes.getFont)
				{
					assignment = new ClosureFontAction(attributes.remove("getFont"))
				}
				else
				{
					assignment = new FontAction()
				}
			}
			else if(ShapeAction.equals(buildClass))
			{
				if(attributes.closure)
				{
					assignment = new ClosureShapeAction(attributes.remove("closure"))
				}
				else if(attributes.getShape)
				{
					assignment = new ClosureShapeAction(attributes.remove("getShape"))
				}
				else
				{
					assignment = new ShapeAction()
				}
			}
			else if(SizeAction.equals(buildClass))
			{
				if(attributes.closure)
				{
					assignment = new ClosureSizeAction(attributes.remove("closure"))
				}
				else if(attributes.getSize)
				{
					assignment = new ClosureSizeAction(attributes.remove("getSize"))
				}
				else
				{
					assignment = new SizeAction()
				}
			}
			else if(StrokeAction.equals(buildClass))
			{
				if(attributes.closure)
				{
					assignment = new ClosureStrokeAction(attributes.remove("closure"))
				}
				else if(attributes.getStroke)
				{
					assignment = new ClosureStrokeAction(attributes.remove("getStroke"))
				}
				else
				{
					assignment = new StrokeAction()
				}
			}
			else if(DataSizeAction.equals(buildClass))
			{
				assignment = new DataSizeAction(builder.pickPrefuseGroup(attributes), attributes.remove("dataField"))
			}
			else if(ColorAction.equals(buildClass))
			{
				if(attributes.closure)
				{
					assignment = new ClosureColorAction(builder.pickPrefuseGroup(attributes), attributes.remove("field"), attributes.remove("closure"))
				}
				else if(attributes.getColor)
				{
					assignment = new ClosureColorAction(builder.pickPrefuseGroup(attributes), attributes.remove("getColor"))
				}
				else
				{
					assignment = new ColorAction(builder.pickPrefuseGroup(attributes), attributes.remove("field"))
				}
				def defaultColor = attributes.remove("defaultColor")
				if(defaultColor != null)
				{
					if(defaultColor instanceof List)
					{
						assignment.setDefaultColor(ColorLib.color(ColorLib.getColor(*defaultColor)))
					}
					else
					{
						assignment.setDefaultColor(defaultColor)
					}
				}
			}
			else if(DataColorAction.equals(buildClass))
			{
				if(attributes.palette && attributes.palette instanceof List)
				{
					//palette should be a list of ints representing colors as created by ColorLib.color(ColorLib.getColor(red, green, blue [, alpha])),
					//But if the user specifies some list entries that are also lists, these sublists will be interpreted as [r,g,b] or [r,g,b,a], converted to int, and replaced in the palette list
					//That way, the user can specify color ints from ColorLib, or [r,g,b]/[r,g,b,a] values, or a mix of the two.
					//e.g. from the Congress demo. The first value in the palette:[list] is an integer value created by the call to Color.rgb, the next 2 values are lists of 3 integers, so [r,g,b]. This will be interpreted as 3 different colors for 3 different data groupings.
					//pfDataColorAction(id:"color", dataField:"Party", dataType:Constants.ORDINAL, field:VisualItem.STROKECOLOR, palette:[ColorLib.rgb(150,150,255), [255,150,150], [180,180,180]]) // dems = blue, reps = red, other = gray
					def palette = attributes.remove("palette")
					def newPalette = []
					palette.each{color->
						if(color instanceof List)
						{
							newPalette << ColorLib.color(ColorLib.getColor(*color))
						}
						else
						{
							newPalette << color
						}
					}
					assignment = new DataColorAction(builder.pickPrefuseGroup(attributes), attributes.remove("dataField"), attributes.remove("dataType"), attributes.remove("field"), newPalette as int[])
				}
				else
				{
					assignment = new DataColorAction(builder.pickPrefuseGroup(attributes), attributes.remove("dataField"), attributes.remove("dataType"), attributes.remove("field"))
				}
			}
			else if(DataShapeAction.equals(buildClass))
			{
				if(attributes.shapes && attributes.shapes instanceof List)
				{
					assignment = new DataShapeAction(builder.pickPrefuseGroup(attributes), attributes.remove("dataField"), attributes.remove("shapes") as int[])
				}
				else
				{
					assignment = new DataShapeAction(builder.pickPrefuseGroup(attributes), attributes.remove("dataField"))
				}
			}
			
			//Try to instantiate the Action with a no-parameter-constructor
			else
			{
				assignment = buildClass.newInstance()
			}
		}

		return assignment
	}
}
